package com.caigaoqing.tech.aspect;

import com.alibaba.fastjson.JSONObject;
import com.caigaoqing.tech.api.UserInfoApi;
import com.caigaoqing.tech.util.IpUtil;
import com.caigaoqing.tech.util.RequestParamsToMap;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * 日志审计
 *
 */
@Component
@Aspect
@Slf4j
public class LogAuditAspect {

	@Autowired
	private UserInfoApi userInfoApi;

	//打印的事件的key
	private final static String REQUEST_PARAM_NAME ="requestParam";
	//打印的ip的key
	private final static String IP_NAME="ip";
	//打印请求的post里面的参数的key
	private final static String POSTBODY_NAME="postBody";
	//打印请求方式的key
	private final static String REQUEST_METHOD_NAME="requestMethod";
	//打印输出数据的key
	private final static String RESPONSE_PARAM_NAME="responseParam";
	//打印客户端系统
	private final static String OS_NAME="os";
	//用户客户端浏览器信息
	private final static String USER_AGENT_NAME="userAgent";
	//打印调用的那个方法的key
	private final static String METHOD_NAME="method";
	//打印方法使用时间的key
	private static final String CONSUME_NAME="consume";
	//获取token的name
	private static final String TOKEN_NAME="token";
	//打印异常的信息的key
	private static final String EXCEPTION_NAME="exception";
	//用户id的key
	private static final String USER_ID_NAME="userId";

	private static final String URL_NAME="url";


	private static final String LOG_MSG_PATTERN_LAYOUT = "{}";

	String token=null;
	private long startTimeMillis = 0; // 开始时间
	private long endTimeMillis = 0; // 结束时间
	private JSONObject logResult=null;


	/**
	 * @param joinPoint
	 * @Description: 方法调用前触发
	 * 记录开始时间
	 */
	public void doBeforeInServiceLayer(JoinPoint joinPoint) {
		startTimeMillis = System.currentTimeMillis(); // 记录方法开始执行的时间
	}

	/**
	 * @param joinPoint
	 * @Description: 方法调用后触发
	 * 记录结束时间
	 */
	public void doAfterInServiceLayer(JoinPoint joinPoint) {
		endTimeMillis = System.currentTimeMillis(); // 记录方法执行完成的时间
		this.printOptLog();
	}

	private static Map<String, Object> parameterMap=new HashMap<String, Object>();;

	private static String userAgent;
	//真实ip
	private static String ip;
	//获得请求的postBody
	private static String postBody;
	// 获取请求方式
	private static String requestMethod;
	//获取uri
	private static String url;

	// 获取请求方法
	private static String method;
	private static Object result;
	/**
	 * @return
	 * @throws Throwable
	 * @Description: 环绕触发
	 */
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

		//获取request信息
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();
		token=request.getHeader(TOKEN_NAME);
		parameterMap = RequestParamsToMap.getParameterMap(request);
		userAgent=request.getHeader("user-agent");
		//真实ip
		ip = IpUtil.getUserIP(request);
		//获得请求的postBody
		postBody=getData(request);
		// 获取请求方式
		requestMethod = request.getMethod();
		//获取uri
		url=request.getRequestURI();

		// 获取请求方法
		method = pjp.getSignature().getDeclaringTypeName() + "."
				+ pjp.getSignature().getName();

		// 执行完方法的返回值：调用proceed()方法，就会触发切入点方法执行
		Object result = pjp.proceed();
		return result;
	}
	/**
	 * 输出日志
	 */
	private void printOptLog() {
		logResult=new JSONObject();
		logResult.put(URL_NAME,url);
		logResult.put(USER_AGENT_NAME,userAgent);
		logResult.put(REQUEST_PARAM_NAME,parameterMap);
		logResult.put(IP_NAME,ip);
		logResult.put(POSTBODY_NAME,postBody);
		logResult.put(REQUEST_METHOD_NAME,requestMethod);
		logResult.put(METHOD_NAME,method);
		logResult.put(RESPONSE_PARAM_NAME,result);
		Long consume= endTimeMillis - startTimeMillis;
		String userId=userInfoApi.getUserIdByToken(token);
		logResult.put(USER_ID_NAME,userId);
		logResult.put(CONSUME_NAME,consume);
		String data=logResult.toString();
		log.info(LOG_MSG_PATTERN_LAYOUT,data);
	}

	public void printExLog(Throwable e){
		logResult=new JSONObject();
		logResult.put(URL_NAME,url);
		logResult.put(USER_AGENT_NAME,userAgent);
		logResult.put(REQUEST_PARAM_NAME,parameterMap);
		logResult.put(IP_NAME,ip);
		logResult.put(POSTBODY_NAME,postBody);
		logResult.put(REQUEST_METHOD_NAME,requestMethod);
		logResult.put(METHOD_NAME,method);
		Long consume= endTimeMillis - startTimeMillis;
		logResult.put(CONSUME_NAME,consume);
		String errorMsg=e.getMessage();
		logResult.put(EXCEPTION_NAME,errorMsg);
		String data=logResult.toString();
		log.error(LOG_MSG_PATTERN_LAYOUT,data);
	}



	private String getData(HttpServletRequest req) throws IOException {
		// 获取post参数
		StringBuffer sb = new StringBuffer();
		InputStream is = req.getInputStream();
		InputStreamReader isr = new InputStreamReader(is);
		BufferedReader br = new BufferedReader(isr);
		String s ;
		while ((s = br.readLine()) != null) {
			sb.append(s);
		}
		return  sb.toString();
	}


}
